package admin

import (
	"fmt"
	"geekai/api/dto/request"
	"geekai/api/dto/response"
	"geekai/api/handler"
	"geekai/core"
	"geekai/core/types"
	"geekai/model"
	"geekai/utils"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"gorm.io/gorm"
	"time"
)

// UserHandler 用户管理模块
type UserHandler struct {
	handler.BaseHandler
	redis *redis.Client
}

func NewUserHandler(app *core.AppServer, db *gorm.DB, client *redis.Client) *UserHandler {
	return &UserHandler{
		BaseHandler: handler.BaseHandler{
			App: app,
			DB:  db,
		},
		redis: client,
	}
}

// List godoc
// @Summary      分页查询用户列表
// @Description  分页查询用户列表
// @Tags         后台管理-用户管理
// @Accept       json
// @Produce      json
// @Param        page      query     int     true  "页码"
// @Param        page_size query     int     true  "页码"
// @Param        username  query     string  false  "用户名称"
// @Success      200  {object}  types.BizVo{data=response.Page}
// @Router       /api/admin/user/list [get]
// @Security AdminApiKeyAuth
func (h *UserHandler) List(c *gin.Context) {
	page := h.GetInt(c, "page", 1)
	pageSize := h.GetInt(c, "page_size", 20)
	username := h.GetTrim(c, "username")
	offset := (page - 1) * pageSize
	var items []model.User
	var users = make([]response.User, 0)
	var total int64
	session := h.DB.Session(&gorm.Session{})
	if username != "" {
		session = session.Where("username like ?", "%"+username+"%")
	}
	// 查询用户数量
	session.Model(&model.User{}).Count(&total)
	res := session.Offset(offset).Limit(pageSize).Order("id desc").Find(&items)
	if res.Error == nil {
		for _, item := range items {
			var user response.User
			err := utils.CopyObject(item, &user)
			if err == nil {
				user.Id = item.Id
				user.CreatedAt = item.CreatedAt.Unix()
				user.UpdatedAt = item.UpdatedAt.Unix()
				users = append(users, user)
			} else {
				log.Errorf("获取用户列表时对象转换出错：%v", err.Error())
			}
		}
	}
	pages := response.NewPage(total, page, pageSize, users)
	utils.SUCCESS(c, pages)
}

// SaveOrUpdate godoc
// @Summary      添加或者修改用户信息
// @Description  添加或者修改用户信息
// @Tags         后台管理-用户管理
// @Accept       json
// @Produce      json
// @Param        req   body     request.UserSaveOrUpdateReq  true  "用户信息"
// @Success      200  {object}  types.BizVo{data=response.User}
// @Router       /api/admin/user/saveOrUpdate [post]
// @Security AdminApiKeyAuth
func (h *UserHandler) SaveOrUpdate(c *gin.Context) {
	var data request.UserSaveOrUpdateReq
	if err := c.ShouldBindJSON(&data); err != nil {
		utils.ERROR(c, types.InvalidArgs)
		return
	}
	var user model.User
	var res *gorm.DB
	var userResp response.User
	// 更新
	if data.Id > 0 {
		// 查询用户信息
		res = h.DB.Where("id", data.Id).First(&user)
		if res.Error != nil {
			utils.ERROR(c, "用户不存在")
			return
		}
		var oldPower = user.Power
		user.Username = data.Username
		user.Email = data.Email
		user.Mobile = data.Mobile
		user.Status = data.Status
		user.Vip = data.Vip
		user.Power = data.Power
		user.ChatRoles = utils.JsonEncode(data.ChatRoles)
		user.ChatModels = utils.JsonEncode(data.ChatModels)
		user.ExpiredTime = utils.Str2stamp(data.ExpiredTime)

		res = h.DB.Select("username", "mobile", "email", "status", "vip",
			"power", "chat_roles_json", "chat_models_json", "expired_time").Updates(&user)
		if res.Error != nil {
			log.Errorf("修改用户信息失败：%v", res.Error)
			utils.ERROR(c, "修改用户信息失败："+res.Error.Error())
			return
		}
		// 记录算力日志
		if oldPower != user.Power {
			mark := types.PowerAdd
			// 使用用户新的算力 减去 旧的算力
			amount := user.Power - oldPower
			// 如果旧的算力大于新的算力，就表示用户的算力被减少了
			if oldPower > user.Power {
				mark = types.PowerSub
				amount = oldPower - user.Power
			}
			// 新增算力日志
			h.DB.Create(&model.PowerLog{
				UserId:    user.Id,
				Username:  user.Username,
				Type:      types.PowerGift,
				Amount:    amount,
				Balance:   user.Power,
				Mark:      mark,
				Model:     "管理员",
				Remark:    fmt.Sprintf("后台管理员强制修改用户算力，修改前：%d，修改后：%d，管理员ID：%d", oldPower, user.Power, h.GetLoginUserId(c)),
				CreatedAt: time.Now(),
			})
		}
		// 如果禁用了用户，则将用户踢下线
		if user.Status == false {
			key := fmt.Sprintf("users/%d", user.Id)
			if _, err := h.redis.Del(c, key).Result(); err != nil {
				log.Errorf("删除用户session失败：%v", err.Error())
			}
		}
	} else {
		// 新增用户
		// 检查用户是否存在
		h.DB.Where("username", data.Username).First(&user)
		if user.Id > 0 {
			utils.ERROR(c, "用户已经存在")
			return
		}
		salt := utils.RandString(8)
		u := model.User{
			Username:    data.Username,
			Email:       data.Email,
			Mobile:      data.Mobile,
			Password:    utils.GenPassword(data.Password, salt),
			Avatar:      "/images/avatar/user.png",
			Salt:        salt,
			Power:       data.Power,
			ChatRoles:   utils.JsonEncode(data.ChatRoles),
			ChatModels:  utils.JsonEncode(data.ChatModels),
			ExpiredTime: utils.Str2stamp(data.ExpiredTime),
			Status:      true,
			Nickname:    fmt.Sprintf("用户@%d", utils.RandomNumber(6)),
		}
		res = h.DB.Create(&u)
		_ = utils.CopyObject(u, &userResp)
		userResp.Id = u.Id
		userResp.CreatedAt = u.CreatedAt.Unix()
		userResp.UpdatedAt = u.UpdatedAt.Unix()
	}
	if res.Error != nil {
		utils.ERROR(c, "用户添加或修改失败："+res.Error.Error())
		return
	}
	utils.SUCCESS(c, userResp)
}

// ResetPass godoc
// @Summary      重置密码
// @Description  重置密码
// @Tags         后台管理-用户管理
// @Accept       json
// @Produce      json
// @Param        req   body     request.UserResetPassReq  true  "用户密码信息"
// @Success      200  {object}  types.BizVo{}
// @Router       /api/admin/user/resetPass [post]
// @Security AdminApiKeyAuth
func (h *UserHandler) ResetPass(c *gin.Context) {
	var data request.UserResetPassReq
	if err := c.ShouldBindJSON(&data); err != nil {
		utils.ERROR(c, types.InvalidArgs)
		return
	}
	// 查询用户信息
	var user model.User
	res := h.DB.First(&user, data.Id)
	if res.Error != nil {
		utils.ERROR(c, "用户不存在")
		return
	}
	password := utils.GenPassword(data.Password, user.Salt)
	user.Password = password
	res = h.DB.Updates(&user)
	if res.Error != nil {
		utils.ERROR(c, "重置密码出现错误："+res.Error.Error())
	} else {
		utils.SUCCESS(c)
	}
}

// Remove godoc
// @Summary      删除用户信息
// @Description  删除用户信息
// @Tags         后台管理-用户管理
// @Accept       json
// @Produce      json
// @Param        id   query     int  false  "用户Id"
// @Param        ids  query     []int  false  "用户Ids"
// @Success      200  {object}  types.BizVo{}
// @Router       /api/admin/user/remove [get]
// @Security AdminApiKeyAuth
func (h *UserHandler) Remove(c *gin.Context) {
	id := c.Query("id")
	ids := c.QueryArray("ids[]")
	if id != "" {
		ids = append(ids, id)
	}
	if len(ids) == 0 {
		utils.ERROR(c, types.InvalidArgs)
		return
	}
	// 开启事务
	tx := h.DB.Begin()
	var err error
	for _, id := range ids {
		// 删除用户
		if err = tx.Where("id", id).Delete(&model.User{}).Error; err != nil {
			break
		}
		// 删除用户会话列表
		// tx.Unscoped()软删除，即设置deleted_at为指定的时间戳
		if err = tx.Unscoped().Where("user_id = ?", id).Delete(&model.ChatItem{}).Error; err != nil {
			break
		}
		// 删除聊天历史记录
		if err = tx.Unscoped().Where("user_id = ?", id).Delete(&model.ChatMessage{}).Error; err != nil {
			break
		}
		// 删除登陆日志
		if err = tx.Where("user_id = ?", id).Delete(&model.UserLoginLog{}).Error; err != nil {
			break
		}
		// 删除算力日志
		if err = tx.Where("user_id = ?", id).Delete(&model.PowerLog{}).Error; err != nil {
			break
		}
		// 删除邀请注册日志
		if err = tx.Where("user_id = ?", id).Delete(&model.InviteLog{}).Error; err != nil {
			break
		}
		// 删除兑换码
		if err = tx.Where("user_id = ?", id).Delete(&model.Redeem{}).Error; err != nil {
			break
		}
		// 删除定时任务
		if err = tx.Where("user_id = ?", id).Delete(&model.MidJourneyJob{}).Error; err != nil {
			break
		}
		if err = tx.Where("user_id = ?", id).Delete(&model.SdJob{}).Error; err != nil {
			break
		}
		if err = tx.Where("user_id = ?", id).Delete(&model.DallJob{}).Error; err != nil {
			break
		}
		if err = tx.Where("user_id = ?", id).Delete(&model.SunoJob{}).Error; err != nil {
			break
		}
		if err = tx.Where("user_id = ?", id).Delete(&model.VideoJob{}).Error; err != nil {
			break
		}
	}
	if err != nil {
		utils.ERROR(c, "删除出现错误："+err.Error())
		tx.Rollback()
		return
	}
	tx.Commit()
	utils.SUCCESS(c)
}

// LoginLog godoc
// @Summary      获取用户登陆记录
// @Description  获取用户登陆记录
// @Tags         后台管理-用户管理
// @Accept       json
// @Produce      json
// @Param        page      query     int     true  "页码"
// @Param        page_size query     int     true  "页码"
// @Success      200  {object}  types.BizVo{data=response.Page}
// @Router       /api/admin/user/loginLog [get]
// @Security AdminApiKeyAuth
func (h *UserHandler) LoginLog(c *gin.Context) {
	page := h.GetInt(c, "page", 1)
	pageSize := h.GetInt(c, "pageSize", 20)
	var total int64
	h.DB.Model(&model.UserLoginLog{}).Count(&total)
	offset := (page - 1) * pageSize
	var items []model.UserLoginLog
	res := h.DB.Offset(offset).Limit(pageSize).Order("id desc").Find(&items)
	if res.Error != nil {
		utils.ERROR(c, "获取数据失败")
		return
	}
	var logs []response.UserLoginLog
	for _, v := range items {
		var logVo response.UserLoginLog
		err := utils.CopyObject(v, &logVo)
		if err == nil {
			logVo.Id = v.Id
			logVo.CreatedAt = v.CreatedAt.Unix()
			logs = append(logs, logVo)
		}
	}
	utils.SUCCESS(c, response.NewPage(total, page, pageSize, logs))
}
